
class Rect(object):
    """
    This class represents a rectangle
    """
 
    def get_left(self):
        return self._left

    def set_left(self, left):
        assert type(left) is int
        dx = left - self._left

        self.move_x(dx)
    left = property(get_left, set_left)


    def get_right(self):
        return self._right

    def set_right(self, right):
        assert type(right) is int
        dx = right - self._right

        self.move_x(dx)
    right = property(get_right, set_right)


    def get_top(self):
        return self._top

    def set_top(self, top):
        assert type(top) is int
        dy = top - self._top

        self.move_y(dy)
    top = property(get_top, set_top)


    def get_bottom(self):
        return self._bottom

    def set_bottom(self, bottom):
        assert type(bottom) is int
        dy = bottom - self._bottom

        self.move_y(dy)
    bottom = property(get_bottom, set_bottom)

   
    def get_topleft(self):
        return (self._left, self._top)

    def set_topleft(self, topleft):
        assert type(topleft) in (tuple, list)
        assert len(topleft) == 2

        self.set_left(topleft[0])
        self.set_top(topleft[1])
    topleft = property(get_topleft, set_topleft)


    def get_topright(self):
        return (self._right, self._top)

    def set_topright(self, topright):
        assert type(topright) in (tuple, list)
        assert len(topright) == 2

        self.set_right(topright[0])
        self.set_top(topright[1])
    topright = property(get_topright, set_topright)


    def get_bottomleft(self):
        return (self._left, self._bottom)

    def set_bottomleft(self, bottomleft):
        assert type(bottomleft) in (tuple, list)
        assert len(bottomleft) == 2

        self.set_left(bottomleft[0])
        self.set_bottom(bottomleft[1])
    bottomleft = property(get_bottomleft, set_bottomleft)


    def get_bottomright(self):
        return (self._right, self._bottom)

    def set_bottomright(self, bottomright):
        assert type(bottomright) in (tuple, list)
        assert len(bottomright) == 2

        self.set_right(bottomright[0])
        self.set_bottom(bottomright[1])
    bottomright = property(get_bottomright, set_bottomright)


    def get_stick(self):
        return self.ystick + self.xstick

    def set_stick(self, stick):
        assert stick in ('topleft', 'topright', 
                         'bottomleft', 'bottomright')
        if stick.startswith('bottom'):
            self.ystick = 'bottom'
        else:
            self.ystick = 'top'

        if stick.endswith('left'):
            self.xstick = 'left'
        else:
            self.xstick = 'right'
    stick = property(get_stick, set_stick)


    def get_xstick(self):
        return self._xstick

    def set_xstick(self, stick):
        assert stick in ('left', 'right')
        self._xstick = stick
    xstick = property(get_xstick, set_xstick)


    def get_ystick(self):
        return self._ystick

    def set_ystick(self, stick):
        assert stick in ('bottom', 'top')
        self._ystick = stick
    ystick = property(get_ystick, set_ystick)


    def get_width(self):
        return self._width

    def set_width(self, width):
        # the rect sticks to self._xstick
        assert type(width) is int
        assert width >= 0

        dw = width - self._width
        assert not (dw < 0 and dw*-1 > self._width)
        
        if self.xstick == 'left':
            self._right += dw

        elif self.xstick == 'right':
            self._left -= dw

        self._width = width
    width = property(get_width, set_width)

    
    def get_height(self):
        return self._height

    def set_height(self, height):
        # the rect sticks to self._ystick
        assert type(height) is int
        assert height >= 0

        dh = height - self._height
        assert not (dh < 0 and dh*-1 > self._height)

        if self.ystick == 'top':
            self._bottom -= dh

        elif self.ystick == 'bottom':
            self._top += dh

        self._height = height
    height = property(get_height, set_height)


    def get_size(self):
        return (self._width, self._height)

    def set_size(self, size):
        # the rect sticks to self.stick
        assert type(size) in (tuple, list)

        self.set_width(size[0])
        self.set_height(size[1])
    size = property(get_size, set_size)


    def move_x(self, dx):
        self._left += dx
        self._right += dx

    def move_y(self, dy):
        self._bottom += dy
        self._top += dy


    def _clash_x(self, rect):
        return (self.left >= rect.left and self.left <= rect.right)\
                or (self.right <= rect.right and self.right >= rect.left)\
                or (self.left <= rect.left and self.right >= rect.right)

    def _clash_y(self, rect):
        return (self.bottom >= rect.bottom and self.bottom <= rect.top)\
                or (self.top <= rect.top and self.top >= rect.bottom)\
                or (self.top >= rect.top and self.bottom <= rect.bottom)

    def clash(self, rect):
        return self._clash_x(rect) and self._clash_y(rect)



    def clip(self, rect):
        """ clips the own rect to the rect and return a new rect"""
        if not self.clash(rect):
            return

        if self.left >= rect.left:
            left = self.left
        else:
            left = rect.left

        if self.right <= rect.right:
            right = self.right
        else:
            right = rect.right

        if self.bottom >= rect.bottom:
            bottom = self.bottom
        else:
            bottom = rect.bottom

        if self.top <= rect.top:
            top = self.top
        else:
            top = rect.top

        width = right - left
        height = top - bottom

        return Rect(left, bottom, width, height)



    def point_collide(self, x, y):
        if x >= self.left and x <= self.right\
           and y >= self.bottom and y <= self.top:
            return True


    def __repr__(self):
        _str = '<Rect('

        if self.stick.endswith('right'):
            _str += 'right: '+str(self.right)+', '
        elif self.stick.endswith('left'):
            _str += 'left: '+str(self.left)+', '

        if self.stick.startswith('bottom'):
            _str += 'bottom: '+str(self.bottom)+', '
        elif self.stick.startswith('top'):
            _str += 'top: '+str(self.top)+', '

        _str += 'width: '+str(self.width)+', '
        _str += 'height: '+str(self.height)+')>'

        return _str


    def __init__(self, left=None, bottom=None, width=None, height=None, 
                 right=None, top=None, stick='bottomleft'):

        if left and right and width:
            if right - left != width:
                raise AttributeError('right - left != width')

        elif left and right:
            width = right - left

        elif left and width:
            right = left + width

        elif right and width:
            left = right - width

        elif left:
            right = left
            width = 0

        elif right:
            left = right
            width = 0

        elif width:
            left = 0
            right = width

        else:
            left = right = width = 0


        if bottom and top and height:
            if top - bottom != height:
                raise AttributeError('top - bottom != height')

        elif bottom and top:
            height = top - bottom

        elif bottom and height:
            top = bottom + height

        elif top and height:
            bottom = top - height

        elif bottom:
            top = bottom
            height = 0

        elif top:
            bottom = top
            height = 0

        elif height:
            bottom = 0
            top = height

        else:
            bottom = top = height = 0

        self._left = left
        self._right = right
        self._bottom = bottom
        self._top = top
        self._width = width
        self._height = height
        self.stick = stick
